#pragma once
#include "../common/net.hpp"
#include <future>

/*
    专门用来接收和发送请求的模块
*/
namespace BRpc
{
    namespace Client
    {
        class Requestor
        {
        public:
            using ptr = std::shared_ptr<Requestor>;
            using RequestCallBack = std::function<void(const BaseMessage::ptr &)>;
            using AsyncResponse = std::future<BaseMessage::ptr>;
            // 将处理一条请求所得到的回应所需的东西描述
            struct RequestDescribe
            {
                using ptr = std::shared_ptr<RequestDescribe>;
                BaseMessage::ptr request;
                RType rtype;
                std::promise<BaseMessage::ptr> response;
                RequestCallBack callback;
            };
            // 接收到信息后
            void onMessage(const BaseConnection::ptr &conn, const BaseMessage::ptr &msg) // conn没用到
            {
                std::string rid = msg->id();
                RequestDescribe::ptr rdp = selectDescribe(rid);
                if (rdp.get() == nullptr)
                {
                    ELOG("收到响应 - %s,但是未找到对应的请求描述!", rid.c_str());
                    return;
                }
                if (rdp->rtype == RType::REQ_ASYNC)
                {
                    rdp->response.set_value(msg);
                }
                else if (rdp->rtype == RType::REQ_CALLBACK)
                {
                    if (rdp->callback)
                        rdp->callback(msg);
                }
                else
                {
                    ELOG("请求类型未知！！");
                }
                // 信息处理完毕删除
                removeDescribe(rid);
            }
            // 异步处理信息
            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, AsyncResponse &async_rsp)
            {
                auto desc = newDescribe(req, RType::REQ_ASYNC);
                if (desc.get() == nullptr)
                {
                    ELOG("构造请求描述对象失败！");
                    return false;
                }
                DLOG("conn send调用");
                conn->send(req);
                async_rsp = desc->response.get_future();
                return true;
            }
            // 同步
            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req,  BaseMessage::ptr &rsp)
            {
                AsyncResponse rsp_future;
                DLOG("requestor send调用");
                bool ret = send(conn, req, rsp_future);
                if (ret == false)
                {
                    return false;
                }
                rsp = rsp_future.get();
                return true;
            }
            // 回调处理信息
            bool send(const BaseConnection::ptr &conn, const BaseMessage::ptr &req, RequestCallBack &cb)
            {
                auto desc = newDescribe(req, RType::REQ_CALLBACK, cb);
                if (desc.get() == nullptr)
                {
                    ELOG("构造请求描述对象失败！");
                    return false;
                }
                conn->send(req);
                return true;
            }

        private:
            // 添加描述对象
            RequestDescribe::ptr newDescribe(const BaseMessage::ptr &req, RType rt, const RequestCallBack &cb = RequestCallBack())
            {
                std::unique_lock<std::mutex> lock(_mutex);
                RequestDescribe::ptr desc =std::make_shared<RequestDescribe>();
                // 如果发送类型是回调并且回调存在
                if (rt == RType::REQ_CALLBACK && cb)
                {
                    desc->callback = cb;
                }
                desc->request = req;
                desc->rtype = rt;
                _request_desc.insert(std::make_pair(req->id(), desc));
                return desc;
            }
            RequestDescribe::ptr selectDescribe(const std::string id)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _request_desc.find(id);
                if (it == _request_desc.end())
                {
                    return RequestDescribe::ptr();
                }
                return it->second;
            }
            bool removeDescribe(const std::string id)
            {
                std::unique_lock<std::mutex> lock(_mutex);
                auto it = _request_desc.find(id);
                if (it == _request_desc.end())
                {
                    ILOG("没有相关的请求描述%s", id);
                    return false;
                }
                _request_desc.erase(id);
                return true;
            }

        private:
            std::mutex _mutex;
            std::unordered_map<std::string, RequestDescribe::ptr> _request_desc;
        };
    }
}